home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / clang / mcomm600.zip / TXZM.C < prev    next >
C/C++ Source or Header  |  1994-10-03  |  58KB  |  1,666 lines

  1.  
  2. /*/////////////////////////////////////////////////////////////////////
  3. //                                                                   //
  4. //  TXZM.C -- zmodem protocol driver (formerly ZMP)                  //
  5. //                                                                   //
  6. //    (c) 1991-94, Mike Dumdei, 6 Holly Lane, Texarkana TX, 75503    //
  7. //                                                                   //
  8. //////////////////////////////////////////////////////////////////// */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdarg.h>
  12. #include <string.h>
  13. #include <process.h>
  14. #include <ctype.h>
  15. #include <io.h>
  16. #include <dos.h>
  17. #include <bios.h>
  18. #include "comm.h"
  19. #include "ansidrv.h"
  20. #include "extra.h"
  21. #include "colors.h"
  22. #include "zmdos.h"
  23.  
  24. #if defined (__TURBOC__)
  25.   #include <dir.h>
  26.   #define ChDrive(d) setdisk((d)-1)
  27.   #pragma warn -par
  28.   #ifdef _RTLENTRY              // BC4 or greater
  29.       #pragma option -x- -RT-
  30.       void _ExceptInit(void) {} // disable exception handling
  31.   #endif
  32. #elif defined (__ZTC__)
  33.   #include <direct.h>
  34.   #define ChDrive(d) _chdrive(d)
  35. #elif defined (__MSC__)
  36.   int ndrives;
  37.   #define ChDrive(d) _dos_setdrive((d), &ndrives)
  38. #endif
  39.  
  40. #define ALT_C       0x2e00
  41. #define ALT_D       0x2000
  42. #define ALT_E       0x1200
  43. #define ALT_H       0x2300
  44. #define ALT_L       0x2600
  45. #define ALT_P       0x1900
  46. #define ALT_R       0x1300
  47. #define ALT_S       0x1f00
  48. #define ALT_X       0x2d00
  49. #define FK1         0x3b00
  50. #define PGUP        0x4900
  51. #define PGDN        0x5100
  52. #define ALT_EQU     0x8300
  53. #define X_ESC       0x011b
  54.  
  55. void AddToList(char *subdir);
  56. char *CaptureBaudRate(void);
  57. char *ConvertSecs(long secs);
  58. int Dial(void);
  59. void DrawBox(int row, int col, int nrows, int ncols, int color, int style);
  60. void DspZmodemScrn(void);
  61. char *ExpandSubDirs(char *fnames);
  62. int FileTransfer(void);
  63. int GetNumber(void);
  64. long getHunds(void);
  65. long getSeconds(void);
  66. void HelpFunc(void);
  67. void InitDefaults(void);
  68. void MiniTermMode(void);
  69. void ProcCmdLine(int argc, char * *argv);
  70. int prompt(char *buf, int maxlen);
  71. void ReadDialDir(void);
  72. int RecurseSubDirs(char *sd);
  73. int RepeatDial(void);
  74. void SetFIFOLevels(int rxFIFOlevel, int txFIFOlevel);
  75. int SetParams(char *newparams);
  76. void usage(void);
  77. void vDisplay(int row, int col, char *format, ...);
  78. int waitfor(int ticks, ...);
  79. void ZMsg(int type, ...);
  80.  
  81. extern int  _C_ TestDesqView(void);
  82. extern int  _C_ DV_VideoSeg(int);
  83. extern void _C_ DV_TimeSlice(void);
  84.  
  85. /*/////////////////////////////////////////////////////////
  86. //  Configuration structure.  Structure is used to allow //
  87. //  the defaults to be changed modifying the EXE.        //
  88. //  "TXZMCFG:" is the tag to search for to find the start//
  89. //  of the structure in the EXE.                         //
  90. //////////////////////////////////////////////////////// */
  91. struct PROTCONFIG
  92. {
  93.     char    tag[8], DLPath[80], ULPath[80];
  94.     long    LocBaud, MinFifoBaud;
  95.     int     ComBase, IRQ, Vctr;
  96.     int     h_VBufSize, h_BufSize, b_VBufSize, b_BufSize;
  97.     int     TxWindow, ZExistOpts, XYExistOpts;
  98.     int     FifoTxLvl, FifoRxLvl;
  99.     char    IgnCarrier, MsrFlow, KeepTime, EscCtl, OvlyIO;
  100.     char    Color[10], Mono[10];
  101. } cfg =
  102. {
  103.     "TXZMCFG:", "", "",
  104.     0L, 1L,
  105.     0x3f8, IRQ4, VCTR4,
  106.     2048, 0, 20508, 20480,
  107.     0, 1, 2,
  108.     8, 8,
  109.     0, 0, 1, 0, 1,
  110.     {  WHT|BLU_B,  H_GRN|BLU_B,  H_RED|BLU_B,    YLW|BLU_B,
  111.        GRY|BLU_B,    YLW|BLU_B,  H_RED|BLU_B,  H_MAG|BLU_B,
  112.        CYN,              CYN_B  },
  113.     { WHT, WHT, RVRS, H_WHT, WHT, H_WHT, H_WHT, H_WHT, WHT, WHT_B }
  114. };
  115.  
  116. /*/////////////////////////////////////////////////////////
  117. //  Screen data structure                                //
  118. //////////////////////////////////////////////////////// */
  119. typedef struct
  120. {
  121.     int row, col, color, count;
  122.     char *text;
  123. } SCREENDATA;
  124.  
  125. /*/////////////////////////////////////////////////////////
  126. //  Dial directory structure                             //
  127. //////////////////////////////////////////////////////// */
  128. static struct DIAL_DIRECTORY
  129. {
  130.     char *num;
  131.     char *name;
  132. } DialDir[10];
  133.  
  134. /*/////////////////////////////////////////////////////////
  135. //  Global variables                                     //
  136. //////////////////////////////////////////////////////// */
  137. ASYNC port;                 /* ASYNC port structure */
  138. int combase, irq, vctr;     /* port address, IRQ number, & vector */
  139. int openmask = 0;           /* mask for forcing no FIFOs, no MSR intrpts */
  140. long LocBaud = 0L;          /* CPU to modem/device baud rate */
  141. char params[12] = "";       /* port parameters */
  142. char lockedbaud[12] = "";   /* locked baud parameter */
  143. char fnames[256] = "";      /* list of files to send if sending */
  144. char minsecs[10];           /* seconds to min:secs buffer */
  145. char *color;                /* pointer to list of colors */
  146. int txtcolor;               /* color of most screen message output */
  147. char buf[256];              /* general purpose buffer */
  148. int goodargs = 0;           /* got an 'r' or an 's' on command line */
  149. char *node = NULL;          /* for bbs use: LASTUSER.BBS format file name */
  150. int miniterm = 0;           /* mini-terminal mode selected */
  151. char OvlyIO;                /* overlay disk and serial I/O flag */
  152. char *flist;                /* used when expanding subdirectories */
  153. char mask[14];              /* used when expanding subdirectories */
  154. int plen;                   /* used when expanding subdirectories */
  155. int tryDV = 0;              /* cmdline switch to test for DesqView */
  156. int checkcarrier = 0;       /* check for carrier during 'waitfor' flag */
  157. int stripmask = 0xff;       /* strip high bit mask for miniterm mode */
  158. char phone[40] = "";        /* phone number to dial */
  159. char DialPrefix[16] = "ATDT"; /* default dial prefix */
  160. char *OverrideName = NULL;  /* cmdline rx filename used if not NULL */
  161. char OverrideFlag = '\0';   /* if '/', above specifies complete pathname */
  162.  
  163. long PrevSecs = -1L;        /* used by getSeconds to handle midnight */
  164. long PrevHunds = -1L;       /* used by getHunds to handle midnight */
  165. long tfBytes, tCPS;         /* total bytes transferred, average CPS */
  166. int tFiles;                 /* number of files transferred */
  167.  
  168. /* variables & dummy function to disable display of file transfer screen */
  169. int qf = 0;
  170. void DoNothing(int r, int c, int a, char *s) {}
  171. void (*DspMsgAt[2])(int, int, int, char *) = { d_msgat, DoNothing };
  172.  
  173.  
  174. /*/////////////////////////////////////////////////////////
  175. //                                                       //
  176. //      Main                                             //
  177. //                                                       //
  178. //:mai////////////////////////////////////////////////// */
  179. void cdecl main(int argc, char *argv[])
  180. {
  181.     int i, FIFOretry = 0;
  182.  
  183.     color = ((initvid() & 0xff) == CO80) ? cfg.Color : cfg.Mono;
  184.     txtcolor = (int)color[1] & 0xff;
  185.     InitDefaults();
  186.     ProcCmdLine(argc, argv);
  187.     if (!goodargs)
  188.         usage();
  189.  
  190.     if (tryDV && TestDesqView() != 0)
  191.     {
  192.         i = DV_VideoSeg(v_seg);
  193.         if (v_seg != i)
  194.             v_seg = i, v_snow = 0;
  195.     }
  196.     if (*params)
  197.         ConnectBaud = atol(params);
  198.     if (*lockedbaud)
  199.         LocBaud = atol(lockedbaud);
  200.     if (LocBaud == 0L)
  201.         LocBaud = ConnectBaud;
  202.     if (LocBaud != 0L)
  203.     {
  204.         sprintf(params, "%ldN81", LocBaud);
  205.         if (LocBaud < cfg.MinFifoBaud)
  206.             openmask |= 0x4000;
  207.     }
  208.  
  209.     if (OvlyIO)
  210.         VBufSize = cfg.h_VBufSize, BufSize = cfg.h_BufSize;
  211.     else
  212.         VBufSize = cfg.b_VBufSize, BufSize = cfg.b_BufSize;
  213.     if (BufSize)
  214.         ZFR0 &= ~CANOVIO;
  215.  
  216.     AllocRingBuffer(&port, 2048, 4096, 0);
  217.     tickhookset(1);
  218.     while (1)
  219.     {
  220.         i = async_open(&port, combase, irq, vctr|openmask, params);
  221.         if (i != 0)
  222.         {
  223.             if (i == 512 && (port.Stat3 & B_FIFO) && FIFOretry == 0
  224.              && !(openmask & 0x4000))
  225.             {
  226.                 openmask |= 0x4000;
  227.                 FIFOretry = 1;      /* FIFO retry code fixes some PCI */
  228.                 continue;           /* serial port lockup problems    */
  229.             }
  230.             tickhookset(0);
  231.             printf("\nSerial port open error, Error code = %d\n\a", i);
  232.             exit(i - 20); /* -20 so exit code don't clash with zm result */
  233.         }
  234.         if (FIFOretry == 1)
  235.         {
  236.             openmask &= ~0x4000;
  237.             FIFOretry = 2;          /* More FIFO retry code.  Opening */
  238.             tdelay(1);              /*  with FIFOs off, closing, and  */
  239.             async_close(&port);     /*  reopening with FIFOs on seems */
  240.             continue;               /*  to unlock the port.           */
  241.         }
  242.         if (ConnectBaud == 0L)
  243.         {
  244.             ConnectBaud = atol(port.BPDSstr);
  245.             strcpy(params, port.BPDSstr);
  246.             if (ConnectBaud < cfg.MinFifoBaud && async_16550(&port)
  247.              && !(openmask & 0x4000))
  248.             {
  249.                 async_close(&port);
  250.                 openmask |= 0x4000;
  251.                 continue;
  252.             }
  253.         }
  254.         break;
  255.     }
  256.     async_msrflow(&port, cfg.MsrFlow);
  257.  
  258.     if (miniterm)
  259.     {
  260.         pushscrn(0, 0, 25, 80);
  261.         SetFIFOLevels(1, 1);
  262.         ReadDialDir();
  263.         MiniTermMode(), i = 0;
  264.         popscrn();
  265.     }
  266.     else
  267.     {
  268.         i = FileTransfer();
  269.         sprintf(buf, "TXZM exit code = %d", i);
  270.         v_color = WHT;
  271.         if (qf == 0)
  272.             d_strat(23, 0, buf);
  273.     }
  274.     async_close(&port);
  275.     tickhookset(0);
  276.     exit(i);
  277. }
  278.  
  279. /*/////////////////////////////////////////////////////////
  280. //  AddToList                                            //
  281. //:add////////////////////////////////////////////////// */
  282. void AddToList(char *subdir)
  283. {
  284.     static char bkslsh[2] = " ";
  285.     int i, j;
  286.  
  287.     if (*(strchr(subdir, '\0') - 1) == '\\' || subdir == GetNameExt(subdir))
  288.         j = 1, *bkslsh = '\0';
  289.     else
  290.         j = 2, *bkslsh = '\\';
  291.     i = plen - 1;
  292.     plen += (strlen(subdir) + strlen(mask) + j);
  293.     flist = realloc(flist, plen);
  294.     sprintf(&flist[i], "\n%s%s%s", subdir, bkslsh, mask);
  295. }
  296.  
  297. /*/////////////////////////////////////////////////////////
  298. //  CaptureBaudRate                                      //
  299. //:cap////////////////////////////////////////////////// */
  300. char *CaptureBaudRate(void)
  301. {
  302.     static char baud[10];
  303.     char *p1 = baud;
  304.     int ch, addzeros = 0;
  305.     long to;
  306.  
  307.     set_timeout(&to, 18);
  308.     do {
  309.         if (async_rxcnt(&port) == 0)
  310.             continue;
  311.         ch = async_rx(&port) & 0x7f;
  312.         d_ch((char)ch);
  313.         if (isdigit(ch))
  314.             *p1++ = ch, --addzeros;
  315.         else if (p1 != baud || ch == '\r')
  316.         {
  317.             if (ch == '.')
  318.             {
  319.                 addzeros = 3;
  320.                 continue;
  321.             }
  322.             while (ch == 'K' && addzeros-- > 0)
  323.                 *p1++ = '0';
  324.             *p1 = '\0';
  325.             if (p1 == baud)
  326.                 strcpy(baud, "300");
  327.             return (baud);
  328.         }
  329.     } while (!timed_out(&to));
  330.     return NULL;
  331. }
  332.  
  333. /*///////////////////////////////////////////////
  334. //  ConvertSecs                                //
  335. //:con//////////////////////////////////////// */
  336. char *ConvertSecs(long secs)
  337. {
  338.     sprintf(minsecs, "%01ld:%02ld   " , uldiv(secs, 60L), ulmod(secs, 60L));
  339.     return(minsecs);
  340. }
  341.  
  342. /*/////////////////////////////////////////////////////////
  343. //  Dial                                                 //
  344. //:dia////////////////////////////////////////////////// */
  345. int Dial(void)
  346. {
  347.     int rval;
  348.     char *p1;
  349.  
  350.     async_txblk(&port, phone, strlen(phone));
  351.     checkcarrier = 0;
  352.     rval = waitfor(45 * 18, "CONNECT", "BUSY", "NO CARRIER", "VOICE",
  353.      "ERROR", "NO DIALTONE", "CARRIER", NULL);
  354.     if (rval == 0 || rval == 6)
  355.     {
  356.         rval = 0;
  357.         if ((p1 = CaptureBaudRate()) != NULL)
  358.             SetParams(p1);
  359.     }
  360.     return (rval);
  361. }
  362.  
  363. /*/////////////////////////////////////////////////////////
  364. //  DrawBox                                              //
  365. //:dra////////////////////////////////////////////////// */
  366. void DrawBox(int row, int col, int nrows, int ncols, int color, int style)
  367. {
  368.     static char boxchars[][6] =
  369.     {
  370.         '┌', '┐', '└', '┘', '─', '│',
  371.         '╔', '╗', '╚', '╝', '═', '║',
  372.         '╒', '╕', '╘', '╛', '═', '│',
  373.         '╓', '╖', '╙', '╜', '─', '║'
  374.     };
  375.     char *box = boxchars[style];
  376.     int temp = v_color;
  377.  
  378.     v_color = color;
  379.     --ncols;
  380.     scrlupat(row, col, row + nrows - 1, col + ncols, nrows);
  381.     --nrows;
  382.     ++col, --ncols, --ncols;
  383.     d_nchat(row, col, box[4], color, ncols, 1);
  384.     d_nchat(row + nrows, col, box[4], color, ncols, 1);
  385.     d_nchat(row, col, box[5], color, nrows, 0);
  386.     d_nchat(row, col + ncols, box[5], color, nrows, 0);
  387.     d_chat(row, col, box[0]);
  388.     d_chat(row, col + ncols, box[1]);
  389.     d_chat(row + nrows, col, box[2]);
  390.     d_chat(row + nrows, col + ncols, box[3]);
  391.     v_color = temp;
  392. }
  393.  
  394. /*/////////////////////////////////////////////////////////
  395. //  DspZmodemScrn                                        //
  396. //:dsp////////////////////////////////////////////////// */
  397. void DspZmodemScrn(void)
  398. {
  399.     static SCREENDATA zscrn[] =
  400.     {
  401.         {  1,  6, 2,   0, " Zmodem File " },
  402.         {  2, 71, 0, -20, "│" },
  403.         { 15,  5, 0,  64, "─" },
  404.         {  2, 73, 0,   0, "F T" },
  405.         {  3, 73, 4, -19, "▒" },
  406.         {  3, 75, 4, -19, "▒" },
  407.         {  3,  5, 0,   0, "File name :" },
  408.         {  5,  5, 0,   0, "Estimated time :" },
  409.         {  6,  5, 0,   0, "Elapsed time   :" },
  410.         {  7,  5, 0,   0, "File CPS rate  :" },
  411.         {  5, 37, 0,   0, "File position      :" },
  412.         {  6, 37, 0,   0, "Expected file size :" },
  413.         {  7, 37, 0,   0, "Beginning offset   :" },
  414.         {  9, 51, 0,   0, "─── Hdr Data ───" },
  415.         { 10, 23, 0,   0, "Header Name" },
  416.         { 10, 40, 0,   0, "Type" },
  417.         { 10, 52, 0,   0, "Hex" },
  418.         { 10, 61, 0,   0, "Decimal" },
  419.         { 11,  5, 0,   0, "Last hdr recvd :" },
  420.         { 12,  5, 0,   0, "Last hdr sent  :" },
  421.         { 14,  5, 0,   0, "Crc :" },
  422.         { 14, 37, 0,   0, "Flow :" },
  423.         { 17,  5, 0,   0, "Total files queued :" },
  424.         { 18,  5, 0,   0, "Total bytes queued :" },
  425.         { 17, 42, 0,   0, "Estimated time   :" },
  426.         { 18, 42, 0,   0, "Accumulated time :" },
  427.         { 20,  5, 0,   0, "Files transferred  :" },
  428.         { 21,  5, 0,   0, "Bytes transferred  :" },
  429.         { 21, 42, 0,   0, "Average CPS rate :" },
  430.         { -1, -1, 0,   0, "" }
  431.     };
  432.     register SCREENDATA *sd;
  433.  
  434.     if (qf != 0)
  435.         return;
  436.     v_color = WHT;
  437.     cls();
  438.     v_color = txtcolor;
  439.     DrawBox(1, 1, 22, 78, color[0], 0);
  440.     for (sd = zscrn; sd->row >= 0; ++sd)
  441.     {
  442.         if (sd->count == 0)
  443.             d_msgat(sd->row, sd->col, color[sd->color], sd->text);
  444.         else if (sd->count > 0)
  445.         {
  446.             d_nchat(sd->row, sd->col, *sd->text, color[sd->color],
  447.              sd->count, 1);
  448.         }
  449.         else
  450.         {
  451.             d_nchat(sd->row, sd->col, *sd->text, color[sd->color],
  452.              -sd->count, 0);
  453.         }
  454.     }
  455.     d_msgat(1, 19, color[2], (TFlag.F.Receiving) ? "Receive " : "Send ");
  456.     loc(23, 0);
  457. }
  458.  
  459. /*/////////////////////////////////////////////////////////
  460. //  ExpandSubDirs                                        //
  461. //:exp////////////////////////////////////////////////// */
  462. char *ExpandSubDirs(char *fnames)
  463. {
  464.     DF fbuf;
  465.     char *p1, *lstptr, *wrkname, *savdir, *orgdir;
  466.     int i, dosub;
  467.  
  468.     orgdir = malloc(_MAX_PATH), getcwd(orgdir, _MAX_PATH);
  469.     wrkname = malloc(_MAX_PATH), savdir = malloc(_MAX_PATH);
  470.     plen = 1, lstptr = SkipSpaces(fnames), flist = calloc(1, 1);
  471.     while (1)
  472.     {
  473.         if (lstptr != fnames)
  474.         {
  475.             if (wrkname[1] == ':')
  476.                 chdir(savdir);
  477.             ChDrive(toupper(*orgdir) - 'A' + 1);
  478.             chdir(orgdir);
  479.         }
  480.         if (*lstptr == '\0')
  481.         {
  482.             free(wrkname), free(orgdir), free(savdir);
  483.             return(flist);
  484.         }
  485.         p1 = lstptr, i = SkipChars(lstptr) - lstptr, dosub = 0;
  486.         lstptr = (SkipSpaces(SkipChars(lstptr)));
  487.         if (*p1 == '(' && p1[i - 1] == ')')
  488.             ++p1, dosub = 2;
  489.         strncpy(wrkname, p1, i), wrkname[i - dosub] = '\0';
  490.         if (wrkname[1] == ':')
  491.         {
  492.             ChDrive(toupper(*wrkname) - 'A' + 1);
  493.             getcwd(savdir, _MAX_PATH);
  494.         }
  495.         p1 = GetNameExt(wrkname);
  496.         strcpy(mask, "*.*");
  497.         if (*p1)
  498.         {
  499.             fbuf.attrib = 0;
  500.             if (!strchr(p1, '*') && !strchr(p1, '?'))
  501.                 DosFindFirst(wrkname, -1, &fbuf);
  502.             if (fbuf.attrib & _A_SUBDIR)
  503.                 p1 = strchr(p1, '\0');
  504.             else
  505.             {
  506.                 strupr(strncpy(mask, p1, 12));
  507.                 p1[0] = mask[12] = '\0';
  508.             }
  509.         }
  510.         if (p1 != wrkname && *(--p1) != ':')
  511.         {
  512.             if (p1 != wrkname && *p1 == '\\' && *(p1 - 1) != ':')
  513.                 *p1 = '\0';
  514.             if (chdir(wrkname) != 0)
  515.                 continue;
  516.         }
  517.         getcwd(wrkname, _MAX_PATH);
  518.         if (dosub == 0)
  519.             AddToList(wrkname);
  520.         else
  521.             RecurseSubDirs(wrkname);
  522.     }
  523. }
  524.  
  525. /*/////////////////////////////////////////////////////////
  526. //  FileTransfer - file send / receive caller            //
  527. //:fil////////////////////////////////////////////////// */
  528. int FileTransfer(void)
  529. {
  530.     FILE *fh;
  531.     int rval, temp = v_color;
  532.     long efficiency = 0L;
  533.  
  534.     if (miniterm)
  535.         pushscrn(0, 0, 24, 80);
  536.     DspZmodemScrn();
  537.     if (node != NULL)           /* BBS support -- Maximus */
  538.     {
  539.         if (qf == 0 && (fh = fopen(node, "rb")) != NULL)
  540.         {
  541.             memset(buf, 0, sizeof(buf));
  542.             fread(buf, 1, sizeof(buf), fh);
  543.             fclose(fh);
  544.             buf[32] = buf[68] = '\0';
  545.             d_msgat(23, 1, WHT, &buf[0]);
  546.             d_msgat(23, 40, WHT, &buf[36]);
  547.         }
  548.     }
  549.     SetFIFOLevels(cfg.FifoRxLvl, cfg.FifoTxLvl);
  550.     ZMsg(M_RESET);
  551.     if (TFlag.F.Receiving)
  552.         rval = ZmodemRecv(&port);
  553.     else
  554.     {
  555.         rval = ZmodemSend(&port, flist);
  556.         free(flist);
  557.     }
  558.     if (ConnectBaud)
  559.         efficiency = uldiv(ulmul(tCPS, 1000L), ConnectBaud);
  560.     sprintf(buf, "\r\nCPS: %ld (%d files, %ld bytes)  Efficiency %ld%%",
  561.      tCPS, tFiles, tfBytes, efficiency);
  562.     if (qf == 0)
  563.     {
  564.         loc(23,1), v_color = WHT;
  565.         d_str(&buf[2]);
  566.     }
  567.     tdelay(4);
  568.     if (node != NULL && async_carrier(&port) && tFiles)
  569.     {                           /* send other end result report */
  570.         async_txblk(&port, buf, strlen(buf));
  571.         async_txblk(&port, "\r\n", 2);
  572.         while (!async_txempty(&port))
  573.             ;
  574.     }
  575.     async_rxflush(&port);
  576.  
  577.     if (miniterm)
  578.     {
  579.         SetFIFOLevels(1, 1);
  580.         d_str(", press ENTER...");
  581.         KBREAD;
  582.         popscrn();
  583.         d_str(buf);
  584.     }
  585.     v_color = temp;
  586.     return (rval);
  587. }
  588.  
  589. /*
  590.     ╔═════════════════════════════════════════════════════════════════════╗
  591.     ║                        TXZM Dialing Directory                       ║
  592.     ║─────────────────────────────────────────────────────────────────────║
  593.     ║  1. North East Texas DataLink               1 (903) 838-6713        ║
  594.     ║  2.                                                                 ║
  595.     ║  3.                                                                 ║
  596.     ║  4.                                                                 ║
  597.     ║  5.                                                                 ║
  598.     ║  6.                                                                 ║
  599.     ║  7.                                                                 ║
  600.     ║  8.                                                                 ║
  601.     ║  9.                                                                 ║
  602.     ║ 10.                                                                 ║
  603.     ║─────────────────────────────────────────────────────────────────────║
  604.     ║ Enter selection (1-10, M - Manual Dial, Esc - Abort):               ║
  605.     ╚═════════════════════════════════════════════════════════════════════╝
  606. */
  607.  
  608. /*/////////////////////////////////////////////////////////
  609. //  GetNumber - get number to dial                       //
  610. //:get////////////////////////////////////////////////// */
  611. int GetNumber(void)
  612. {
  613.     const int r = 3, l = 4;
  614.     int i, tmp1 = txtcolor, tmp2 = v_color, tmp3 = qf;
  615.     char buf[3];
  616.  
  617.     if (*DialDir[0].num == '\0')
  618.         return (-1);
  619.     pushscrn(r, l, 16, 71);
  620.     txtcolor = (int)color[0] & 0xff;
  621.     v_color = txtcolor | 0x08;
  622.     DrawBox(r, l, 16, 71, txtcolor, 1);
  623.     d_nchat(r+2, l+2, '─', txtcolor, 67, 1);
  624.     d_nchat(r+13, l+2, '─', txtcolor, 67, 1);
  625.     d_strat(r+1, l+25, "TXZM Dialing Directory");
  626.     d_strat(r+14, l+3,
  627.      "Enter selection (1-10, M - Manual Dial, Esc - Abort): ");
  628.     for (i = qf = 0; i < 10; ++i)
  629.     {
  630.         vDisplay(r+i+3, l+3, "%2d. %-38s  %s", i + 1, DialDir[i].name,
  631.          DialDir[i].num);
  632.     }
  633.     while (1)
  634.     {
  635.         d_strat(r+14, l+57, "  \b\b");
  636.         i = 0;
  637.         if (prompt(buf, 2) == 0)
  638.             break;
  639.         i = -1;
  640.         if (*buf == 'M' || *buf == 'm')
  641.             break;
  642.         if ((i = atoi(buf)) >= 0 && i <= 10)
  643.             break;
  644.     }
  645.     txtcolor = tmp1, v_color = tmp2, qf = tmp3;
  646.     popscrn();
  647.     return (i);
  648. }
  649.  
  650. /*/////////////////////////////////////////////////////////
  651. //  HelpFunc - display help screen                       //
  652. //:hel////////////////////////////////////////////////// */
  653. void HelpFunc(void)
  654. {
  655.     static char helpscrn[] = "\n\
  656.     -- TXZM COMMANDS --\n\
  657.   ALT X:  Exit program         ALT E:  Echo On\n\
  658.   ALT S:  Shell to DOS         ALT P:  Change Baud\n\
  659.   ALT D:  Dial Number          ALT =:  Doorway Mode\n\
  660.   ALT R:  Redial Number        PGUP :  Send Zmodem\n\
  661.   ALT H:  Hang Up              PGDN :  Receive Zmodem\n\
  662.   ALT L:  Toggle Log File (TXZM.CAP)\n";
  663.  
  664.     d_str(helpscrn);
  665. }
  666.  
  667. /*/////////////////////////////////////////////////////////
  668. //  InitDefaults - init protocol global variables        //
  669. //:ini////////////////////////////////////////////////// */
  670. void InitDefaults(void)
  671. {
  672.     combase = cfg.ComBase, irq = cfg.IRQ, vctr = cfg.Vctr;
  673.     LocBaud = cfg.LocBaud;
  674.     OvlyIO = cfg.OvlyIO;
  675.     TFlag.F.ExistOpts = cfg.ZExistOpts;
  676.     TFlag.F.IgnCarrier = cfg.IgnCarrier;
  677.     TFlag.F.KeepTime = cfg.KeepTime;
  678.     TFlag.F.EscCtl = cfg.EscCtl;
  679.     TxWindow = cfg.TxWindow;
  680. }
  681.  
  682. /*/////////////////////////////////////////////////////////
  683. //  MiniTermMode - mini-terminal mode                    //
  684. //:min////////////////////////////////////////////////// */
  685. void MiniTermMode(void)
  686. {
  687.     static char rxtripstr[6] = { '*', '*', ZDLE, 'B', '0', '0' };
  688.     static FILE *flog = NULL;
  689.     int ch, rxtrip = 0, echo = 0, doorwaymode = 0;
  690.     char *cmd;
  691.     static char statline[] = "\
  692.  Help F1 | Exit ALT-X | Shell ALT-S | Hangup ALT-H | Send PGUP | Recv PGDN";
  693.  
  694.     cmd = getenv("COMSPEC");
  695.     if (cmd == NULL)
  696.         cmd = "COMMAND";
  697.     v_color = color[8];
  698.     cls();
  699.     sprintf(buf,
  700.      "TXZM 2.41 Mini-Terminal Mode : %s : (c) 1994 Mike Dumdei\n\n",
  701.      port.BPDSstr);
  702.     d_strat(1, 0, buf);
  703.     d_nchat(24, 0, ' ', color[9], 80, 1);
  704.     d_msgat(24, 1, color[9], statline);
  705.     SETWND(0, 0, 23, 79);
  706.     while (1)
  707.     {
  708.         if (KBHIT)
  709.         {
  710.             if ((unsigned)(ch = KBREAD) == ALT_EQU)
  711.             {
  712.                 if ((doorwaymode ^= 1) != 0)
  713.                 {
  714.                     v_btm = 24;
  715.                     d_nchat(24, 0, ' ', v_color, 80, 1);
  716.                 }
  717.                 else
  718.                 {
  719.                     if (((ch = getcurloc()) >> 8) == 24)
  720.                         d_ch('\n'), loc(23, (char)(ch & 0xff));
  721.                     v_btm = 23;
  722.                     d_nchat(24, 0, ' ', color[9], 80, 1);
  723.                     d_msgat(24, 1, color[9], statline);
  724.                 }
  725.             }
  726.             else if (doorwaymode)
  727.             {
  728.                 if (!(ch & 0xff))
  729.                 {
  730.                     async_tx(&port, '\0');
  731.                     ch >>= 8;
  732.                 }
  733.                 async_tx(&port, (char)ch);
  734.             }
  735.             else switch (ch)
  736.             {
  737.               case FK1:
  738.                 HelpFunc();
  739.                 break;
  740.               case ALT_C:
  741.                 v_color = 7;
  742.                 cls();
  743.                 break;
  744.               case ALT_X:
  745.                 return;
  746.               case ALT_H:
  747.                 async_dtr(&port, 0);
  748.                 tdelay(9);
  749.                 async_dtr(&port, 1);
  750.                 break;
  751.               case ALT_D:
  752.                 if ((ch = GetNumber()) == 0)
  753.                     break;
  754.                 if (ch > 0)
  755.                     strcpy(buf, DialDir[ch - 1].num);
  756.                 else
  757.                 {
  758.                     d_str("\nEnter number to dial (ESC to abort) :\n");
  759.                     if ((ch = prompt(buf, 32)) == 0)
  760.                         break;
  761.                 }
  762.                 sprintf(phone, "%s%s\r", DialPrefix, buf);
  763.                 Dial();
  764.                 break;
  765.               case ALT_R:
  766.                 if (*phone)
  767.                     RepeatDial();
  768.                 break;
  769.               case ALT_P:
  770.                 SetParams(NULL);
  771.                 break;
  772.               case ALT_L:
  773.                 if (flog)
  774.                 {
  775.                     fclose(flog);
  776.                     flog = NULL;
  777.                     d_str("\nTXZM.CAP file closed\n");
  778.                 }
  779.                 else
  780.                 {
  781.                     if ((flog = fopen("TXZM.CAP", "ab")) != NULL)
  782.                         d_str("\nTXZM.CAP file opened\n");
  783.                     else
  784.                         d_str("\nTXZM.CAP file open error\n");
  785.                 }
  786.                 break;
  787.               case ALT_E:
  788.                 echo ^= 1;
  789.                 break;
  790.               case ALT_S:
  791.                 pushscrn(0, 0, 25, 80);
  792.                 SETWND(0, 0, 24, 79);
  793.                 cls();
  794.                 d_str("Type EXIT and press ENTER to return to TXZM MiniTerm\n");
  795.                 spawnlp(P_WAIT, cmd, cmd, NULL);
  796.                 popscrn();
  797.                 SETWND(0, 0, 23, 79);
  798.                 break;
  799.               case PGUP:
  800.                 d_str("\nEnter filenames to send (ESC to abort) :\n");
  801.                 if ((ch = prompt(fnames, 255)) == 0)
  802.                     break;
  803.                 flist = ExpandSubDirs(fnames);
  804.                 TFlag.F.Receiving = 0;
  805.                 FileTransfer();
  806.                 break;
  807.               case PGDN:
  808.                 TFlag.F.Receiving = 1;
  809.                 FileTransfer();
  810.                 rxtrip = 0;
  811.                 break;
  812.               default:
  813.                 if (ch & 0xff)
  814.                 {
  815.                     async_tx(&port, (char)ch);
  816.                     if (echo)
  817.                     {
  818.                         d_ch((char)ch);
  819.                         if (flog)
  820.                             fputc(ch, flog);
  821.                     }
  822.                 }
  823.                 break;
  824.             }
  825.         }
  826.         else if (async_rxcnt(&port))
  827.         {
  828.             ch = async_rx(&port) & stripmask;
  829.             d_ch((char)ch);
  830.             if (ch != rxtripstr[rxtrip++])
  831.                 rxtrip = 0;
  832.             if (flog)
  833.                 fputc(ch, flog);
  834.             if (rxtrip == 6)
  835.             {
  836.                 TFlag.F.Receiving = 1;
  837.                 FileTransfer();
  838.                 rxtrip = 0;
  839.             }
  840.  
  841.         }
  842.         else if (tryDV)
  843.             DV_TimeSlice();
  844.     }
  845. }
  846.  
  847. /*/////////////////////////////////////////////////////////
  848. //  ProcCmdLine -- process commnad line args             //
  849. //:pro////////////////////////////////////////////////// */
  850. void ProcCmdLine(int argc, char *argv[])
  851. {
  852.                         /*   COM1   COM2   COM3   COM4  */
  853.     static int bases[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
  854.     static int irqs[4]  = {  IRQ4,  IRQ3,  IRQ4,  IRQ3 };
  855.     static int vctrs[4] = { VCTR4, VCTR3, VCTR4, VCTR3 };
  856.     FILE *fh;
  857.     int parg = 0, i, j;
  858.     char *p1;
  859.  
  860.     for (i = 1; i < argc; i++)
  861.     {
  862.         p1 = strupr(argv[i]);
  863.         if (*p1 == '-' || *p1 == '/')
  864.             ++p1;
  865.         if (parg == 0)
  866.         {
  867.             if (strncmp(argv[i], "COM", 3) == 0)
  868.             {
  869.                 j = atoi(isdigit(*(p1 += 3)) ? p1 : argv[++i]);
  870.                 if (j < 1 && j > 4)
  871.                     usage();
  872.                 --j, parg = 1;
  873.                 combase = bases[j], irq = irqs[j], vctr = vctrs[j];
  874.                 continue;
  875.             }
  876.         }
  877.         switch (*p1)
  878.         {
  879.           case 'C':             /* custom comm port */
  880.             if (!isxdigit(*++p1))
  881.                 p1 = argv[++i];
  882.             for (combase = 0; isxdigit(*p1); ++p1)
  883.             {
  884.                 combase = (combase << 4) | (*p1 - ((*p1 > '9' ) ?
  885.                  ('A' - 0xA) : '0'));
  886.             }
  887.             irq = atoi(&p1[1]);
  888.             if (irq < 2 || irq > 15 || parg)
  889.                 usage();
  890.             if (irq < 8)        /* IRQ between 0 & 7 */
  891.                 vctr = irq + 8, irq = 1 << irq;
  892.             else                /* IRQ between 8 & 15 (uses AT slave 8259) */
  893.                 vctr = irq + 104, irq = 1 << (irq - 8);
  894.             parg = 1;
  895.             break;
  896.           case 'B':             /* connect baud rate */
  897.             strcpy(params, (isdigit(*++p1)) ? p1 : argv[++i]);
  898.             break;
  899.           case 'L':             /* locked baud rate */
  900.             strcpy(lockedbaud, (isdigit(*++p1)) ? p1 : argv[++i]);
  901.             break;
  902.           case 'D':             /* disable FIFOs */
  903.             openmask |= 0x4000;
  904.             break;
  905.           case 'M':             /* disable MSR interrupts */
  906.             openmask |= 0x2000;
  907.             break;
  908.           case 'H':             /* enable hardware handshake */
  909.             if (!isdigit(*++p1) || (j = atoi(p1)) < 0 || j > 3)
  910.                 j = 3;
  911.             if (j & 1)
  912.                 cfg.MsrFlow = B_CTS;    /* sender monitors CTS */
  913.             if (j & 2)
  914.                 cfg.MsrFlow |= B_RTS;   /* recvr drops RTS if rxbuf fills */
  915.             break;
  916.           case 'P':             /* send/accept complete pathnames */
  917.             TFlag.F.FullPath = 1;
  918.             break;
  919.           case 'I':             /* ignore loss of carrier */
  920.             TFlag.F.IgnCarrier = 1;
  921.             break;
  922.           case 'E':             /* option to take if file exists */
  923.             if (isdigit(*++p1) && (j = atoi(p1)) >= 0 && j <= 3)
  924.                 TFlag.F.ExistOpts = j;
  925.             break;
  926.           case 'X':             /* escape control characters */
  927.             ++p1;
  928.             if (!isdigit(*p1) && *p1 != '-' && !isdigit(*argv[i + 1])
  929.              && *argv[i + 1] != '-')
  930.                 TFlag.F.EscCtl = 1;
  931.             else
  932.             {
  933.                 if (!isdigit(*p1) && *p1 != '-')
  934.                     p1 = argv[++i];
  935.                 do {
  936.                     j = atoi(p1);
  937.                     if ((j & 0xff60) == 0)
  938.                         ZTable[j] &= 0xf7;
  939.                     else if (j < 0 && (-j & 0xff60) == 0)
  940.                     {
  941.                         if (j == -17)         /* XON char */
  942.                             ZTable[17] = 0x8b, ZTable[128+17] = 0x0b;
  943.                         else if (j == -19)    /* XOFF char */
  944.                             ZTable[19] = 0x8b, ZTable[128+19] = 0x0b;
  945.                         else
  946.                             ZTable[-j] |= 0x08;
  947.                     }
  948.                     p1 = SkipSpaces(SkipChars(p1));
  949.                 } while (*p1);
  950.             }
  951.             break;
  952.           case 'V':             /* disable disk writes during serial I/O */
  953.             OvlyIO = 0;
  954.             break;
  955.           case 'W':             /* maximum tx bytes in transit */
  956.             TxWindow = atoi(isdigit(*++p1) ? p1 : argv[++i]);
  957.             break;
  958.           case 'N':             /* bbs use, node number follows */
  959.             node = (*++p1) ? p1 : argv[++i];
  960.             break;
  961.           case '6':             /* 16 bit CRCs only */
  962.             ZFR0 &= ~CANFC32;
  963.             break;
  964.           case '7':             /* strip high bit in mini-term mode */
  965.             stripmask = 0x7f;
  966.             break;
  967.           case '0':
  968.             v_bios = 1;         /* use bios for video */
  969.             break;
  970.           case 'Q':             /* test for DesqView environment */
  971.             tryDV = 1;
  972.             break;
  973.           case '!':  /* send hidden, keep file atrib, hide subs with FF or % */
  974.             TFlag.F.SendHid = TFlag.F.KeepAtrib = TFlag.F.HideSubs = 1;
  975.             break;
  976.           case 'U':             /* miniterm mode */
  977.             miniterm = goodargs = 1;
  978.             break;
  979.           case 'Y':             /* override incoming filename */
  980.             TFlag.F.ExistOpts = 3;
  981.             OverrideFlag = *(p1 - 1);
  982.             OverrideName = (*++p1) ? p1 : argv[++i];
  983.             break;
  984.           case '$':             /* don't display file transfer screen */
  985.             qf = 1;
  986.             break;
  987.           case 'R':             /* receiving -- download path may follow */
  988.             TFlag.F.Receiving = 1;
  989.             if (*++p1 > ' ')
  990.                 DfltPath = p1;
  991.             else if (++i < argc)
  992.                 DfltPath = argv[i];
  993.             else
  994.                 DfltPath = cfg.DLPath;
  995.             i = argc;
  996.             ++goodargs;
  997.             break;
  998.           case 'S':             /* sending -- file names next args */
  999.             TFlag.F.Receiving = 0;
  1000.             DfltPath = cfg.ULPath;
  1001.             if (*++p1 > ' ')
  1002.                 argv[i--] = p1;
  1003.             if (*argv[i + 1] == '@')
  1004.             {
  1005.                 if ((fh = fopen(&argv[++i][1], "rb")) == NULL)
  1006.                     break;
  1007.                 j = (int)filelength(fileno(fh));
  1008.                 if ((p1 = calloc(j + 1, 1)) == NULL)
  1009.                 {
  1010.                     fclose(fh);
  1011.                     break;
  1012.                 }
  1013.                 fread(p1, 1, j, fh);
  1014.                 fclose(fh);
  1015.                 flist = ExpandSubDirs(p1);
  1016.                 free(p1);
  1017.                 i = argc;
  1018.                 --goodargs;
  1019.             }
  1020.             else
  1021.             {
  1022.                 while (++i < argc)
  1023.                 {
  1024.                     strcat(fnames, " ");
  1025.                     strcat(fnames, argv[i]);
  1026.                     flist = ExpandSubDirs(fnames);
  1027.                 }
  1028.                 if (fnames[1])
  1029.                     --goodargs;
  1030.             }
  1031.             break;
  1032.         }
  1033.     }
  1034. }
  1035.  
  1036. /*/////////////////////////////////////////////////////////
  1037. //  Prompt - prompt for input string                     //
  1038. //:pro////////////////////////////////////////////////// */
  1039. int prompt(char *buf, int maxlen)
  1040. {
  1041.     char *p1 = buf;
  1042.     int ch = 0;
  1043.  
  1044.     while (ch != '\r' && ch != '\x1b')
  1045.     {
  1046.         if ((ch = (KBREAD & 0xff)) == '\r')
  1047.             continue;
  1048.         if (ch == '\b')
  1049.         {
  1050.             if (p1 > buf)
  1051.                 d_ch((char)ch), --p1;
  1052.         }
  1053.         else if (p1 >= &buf[maxlen])
  1054.             d_ch('\a');
  1055.         else if (ch != '\x1b' && isprint(ch))
  1056.             d_ch((char)ch), *p1++ = ch;
  1057.     }
  1058.     d_ch('\n');
  1059.     if (ch == '\x1b')
  1060.         p1 = buf;
  1061.     *p1 = '\0';
  1062.     return (*buf);
  1063. }
  1064.  
  1065. /*/////////////////////////////////////////////////////////
  1066. //  ReadDialDir                                          //
  1067. //:rea////////////////////////////////////////////////// */
  1068. void ReadDialDir(void)
  1069. {
  1070.     FILE *fh;
  1071.     char *p1 = getenv("TXZMDIAL"), *p2;
  1072.     static char *nulstr = "";
  1073.     int i;
  1074.  
  1075.     for (i = 0; i < 10; ++i)
  1076.         DialDir[i].name = DialDir[i].num = nulstr;
  1077.     if (p1 == NULL)
  1078.         p1 = "TXZMDIAL.DIR";
  1079.     if ((fh = fopen(p1, "rb")) == NULL)
  1080.         return;
  1081.     for (i = 0; i < 10 && fgets(buf, 255, fh); )
  1082.     {
  1083.         if (isspace(*buf) || *buf == ';')
  1084.             continue;
  1085.         if ((p1 = strchr(buf, '\r')) != NULL)
  1086.             *p1 = '\0';
  1087.         if ((p2 = strchr(buf, ':')) == NULL)
  1088.             p2 = strchr(buf, '\0');
  1089.         else
  1090.         {
  1091.             if (memicmp(buf, "ModemInit", 9) == 0)
  1092.             {
  1093.                 ++p2;
  1094.                 while (!async_carrier(&port) && *p2)
  1095.                 {
  1096.                     switch (*p2)
  1097.                     {
  1098.                       case '|':
  1099.                         async_tx(&port, '\r');
  1100.                         break;
  1101.                       case '^':
  1102.                         async_dtr(&port, 1);
  1103.                         break;
  1104.                       case 'v':
  1105.                         async_dtr(&port, 0);
  1106.                         break;
  1107.                       case '`':
  1108.                         tdelay(2);
  1109.                         break;
  1110.                       case '~':
  1111.                         tdelay(18);
  1112.                         break;
  1113.                       case '!':
  1114.                         qf = 1;
  1115.                         waitfor(72, "OK", NULL);
  1116.                         qf = 0;
  1117.                         tdelay(2);
  1118.                         break;
  1119.                       default:
  1120.                         async_tx(&port, *p2);
  1121.                         break;
  1122.                     }
  1123.                     ++p2;
  1124.                 }
  1125.                 continue;
  1126.             }
  1127.             else if (memicmp(buf, "DialPrefix", 10) == 0)
  1128.             {
  1129.                 strncpy(DialPrefix, ++p2, 15);
  1130.                 continue;
  1131.             }
  1132.             else
  1133.             {
  1134.                 p2[38] = '\0';
  1135.                 DialDir[i].name = strdup(p2 + 1);
  1136.             }
  1137.         }
  1138.         while (--p2 > buf && isspace(*p2))
  1139.             ;
  1140.         *++p2 = '\0';
  1141.         DialDir[i].num = strdup(buf);
  1142.         ++i;
  1143.     }
  1144.     fclose(fh);
  1145. }
  1146.  
  1147. /*/////////////////////////////////////////////////////////
  1148. //  RecurseSubDirs                                       //
  1149. //:rec////////////////////////////////////////////////// */
  1150. int RecurseSubDirs(char *sd)
  1151. {
  1152.     DF fbuf;
  1153.     static char subdir[_MAX_PATH];
  1154.     int mask = (TFlag.F.SendHid) ? _A_SUBDIR|_A_HIDDEN : _A_SUBDIR;
  1155.  
  1156.     if (chdir(sd) != 0)
  1157.         return 0;
  1158.     getcwd(subdir, _MAX_PATH);
  1159.     AddToList(subdir);
  1160.     if (!DosFindFirst("*.*", mask, &fbuf))
  1161.     {
  1162.         do {
  1163.             if (fbuf.attrib & _A_SUBDIR && fbuf.name[0] != '.')
  1164.                 RecurseSubDirs(fbuf.name);
  1165.         } while (!DosFindNext(&fbuf));
  1166.     }
  1167.     chdir("..");
  1168.     getcwd(subdir, _MAX_PATH);
  1169.     return 1;
  1170. }
  1171.  
  1172. /*/////////////////////////////////////////////////////////
  1173. //  RepeatDial                                           //
  1174. //:rep////////////////////////////////////////////////// */
  1175. int RepeatDial(void)
  1176. {
  1177.     int rval, dials = 0, curpos = getcurloc();
  1178.     char buf[40];
  1179.  
  1180.     while ((rval = Dial()) != 0 && rval != X_ESC)
  1181.     {
  1182.         tdelay(36);
  1183.         while (async_rxcnt(&port))
  1184.             d_ch((char)async_rx(&port));
  1185.         sprintf(buf, "Dial Attempts = %d", ++dials);
  1186.         d_str(buf);
  1187.         setcurloc(curpos);
  1188.     }
  1189.     return (rval);
  1190. }
  1191.  
  1192. /*/////////////////////////////////////////////////////////
  1193. //  SetFIFOLevels - set FIFO levels                      //
  1194. //:set////////////////////////////////////////////////// */
  1195. void SetFIFOLevels(int rxFIFOlevel, int txFIFOlevel)
  1196. {
  1197.     if (port.Stat3 & B_FIFO)
  1198.     {
  1199.         async_FIFOrxlvl(&port, rxFIFOlevel);
  1200.         async_FIFOtxlvl(&port, txFIFOlevel);
  1201.     }
  1202. }
  1203.  
  1204. /*/////////////////////////////////////////////////////////
  1205. //  SetParams - set comport parameters                   //
  1206. //:set////////////////////////////////////////////////// */
  1207. int SetParams(char *newparams)
  1208. {
  1209.     if (newparams != NULL)
  1210.         strcpy(buf, newparams);
  1211.     else
  1212.     {
  1213.         d_str("\nEnter modem parameters (ESC to abort) :\n");
  1214.         if (prompt(buf, 9) == 0)
  1215.             return 0;
  1216.     }
  1217.     ConnectBaud = atol(buf);
  1218.     if (*lockedbaud == '\0')
  1219.     {
  1220.         if (*(strrchr(buf, '0') + 1) == '\0')
  1221.             strcat(buf, strrchr(params, '0') + 1);
  1222.         strupr(buf);
  1223.         if (async_setbpds(&port, buf) != 0) /* if no good */
  1224.         {
  1225.             ConnectBaud = atol(params);
  1226.             return 0;
  1227.         }
  1228.         strcpy(params, buf);
  1229.         LocBaud = ConnectBaud;
  1230.     }
  1231.     sprintf(buf,"\nModem Parameters: %s, ConnectBaud: %ld, LockedBaud: %ld\n",
  1232.       port.BPDSstr, ConnectBaud, (*lockedbaud) ? LocBaud : 0L);
  1233.     d_str(buf);
  1234.     return 1;
  1235. }
  1236.  
  1237. /*///////////////////////////////////////////////
  1238. //  Usage                                      //
  1239. //:usa//////////////////////////////////////// */
  1240. void usage()
  1241. {
  1242.     static char msg1[] = "\n\
  1243. \
  1244. TXZM -- Zmodem Protocol Driver 2.41\n\
  1245.  (c) 1994, Mike Dumdei, 6 Holly Lane, Texarkana Tx 75503\n\
  1246. \n\
  1247. This program is a demo of the MCOMM5 'C' serial communications library.\n\
  1248. It may be used free of charge for non-commercial purposes.  It is not\n\
  1249. public domain and may not be modified, sold, or distributed for a fee\n\
  1250. with the exception of normal and reasonable shareware distribution fees.\n\
  1251. \n\
  1252. If you have a need for a C communications library, the latest shareware\n\
  1253. version of MCOMM5 (freq = MCOMM) is available from:\n\
  1254.   North East Texas DataLink BBS, Texarkana TX  (903) 838-6713  1:3819/128\n\
  1255. Features of MCOMM5 include:\n\
  1256.   Fully interrupt driven            16550 FIFO support\n\
  1257.   Up to 115200 baud                 Fast - 95%% ASM code\n\
  1258.   Library version: $25, Source included: $45\n\
  1259. \n\
  1260. << TXZM USAGE: >>\n\
  1261.   recv> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -v -e# } -r {directory}\n\
  1262.   send> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -w#    } -s file1 file2\n\
  1263.   term> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -w# -v -e# } -u\n\
  1264. Arguments in braces are optional.  If a baud rate is not specified, the\n\
  1265. current baud rate will be used.  The -r or -s switches must come last\n\
  1266. on the command line.\n\
  1267. Press any key for command line switch descriptions.....";
  1268.  
  1269.     static char msg2[] = "\n\
  1270. \n\
  1271.  port : set to COM1 (default), COM2, COM3, COM4, or -c#,#\n\
  1272.          -c#,# : base port address of comm port in hex,IRQ (2-15)\n\
  1273.          Ex: -c2E8,5    Addrs=2E8 IRQ=5  (no spaces in arg)\n\
  1274.   -b# : baud rate -- if using a fixed DTE link, CONNECT baud rate\n\
  1275.   -l# : baud rate of fixed DTE link (locked baud rate)\n\
  1276.   -t# : maximum characters to send to 16550 FIFOs per interrupt\n\
  1277.          1-16, default is 8  (some modems may require lower setting)\n\
  1278.   -d  : if 16550 UART detected do not enable FIFOs, default is to enable\n\
  1279.   -m  : disable modem status register interrupts\n\
  1280.   -h  : use RTS/CTS hardware handshake\n\
  1281.   -i  : ignore absence of carrier detect\n\
  1282.   -p  : send/accept full pathnames (will create subdirs)\n\
  1283.   -q  : DesqView mode (use DV video buffer, timeslice when idle)\n\
  1284.   -x  : zdle escape all control characters, -x#,.. to esc particular chars\n\
  1285.   -v  : disable serial I/O during disk writes\n\
  1286.   -e# : duplicate file handling options (default = 1)\n\
  1287.          0=skip file, 1=resume transfer, 2=create dup name, 3=overwrite\n\
  1288.   -w# : transmit window size (must be multiple of 128)\n\
  1289.   -u  : start up in mini-terminal mode\n\
  1290.   -r  : receive,  directory is optional download directory\n\
  1291.   -s  : send, file names follow - recurses subdirs of names in parenthensis\n\
  1292. txzm com2 -b2400 -h -e2 -r   (COM2, 2400 baud, CTS hndshk, dup name if exist)\n\
  1293. txzm -l38400 -b9600 -s *.zip (38400 locked rate, 9600 CONNECT, send all ZIPs)\n\
  1294. txzm -p -s (c:\\subdir)       (send all files in all subdirs in c:\\subdir)";
  1295.  
  1296.     cls();
  1297.     printf(msg1);
  1298.     KBREAD;
  1299.     printf(msg2);
  1300.     exit(-100);
  1301. }
  1302.  
  1303. /*///////////////////////////////////////////////
  1304. //  vDisplay                                   //
  1305. //:vdi//////////////////////////////////////// */
  1306. void vDisplay(int row, int col, char *format, ...)
  1307. {
  1308.     va_list arg_ptr;
  1309.     char lbuf[80];
  1310.  
  1311.     va_start(arg_ptr, format);
  1312.     vsprintf(lbuf, format, arg_ptr);
  1313.     DspMsgAt[qf](row, col, txtcolor, lbuf);
  1314. }
  1315.  
  1316. /* ////////////////////////////////////////////////////////////////
  1317. //  waitfor -  waits for one of a list of up to 10 different     //
  1318. //   strings to come in on the serial port.  The list must end   //
  1319. //   with NULL.  The ticks argument is how long to wait and is   //
  1320. //   in 1/18s of a second.  Calls MCOMM serial and timer LIB     //
  1321. //   functions.  Returns the index of the first targeted string  //
  1322. //   found or one of the above error values.                     //
  1323. //:wai////////////////////////////////////////////////////////// */
  1324. int waitfor(int ticks, ...)
  1325. {
  1326.     struct { int len; char *str; } list[11], *wp;
  1327.     va_list argptr;
  1328.     char ch, *p1, *buf;
  1329.     long to;
  1330.     int i, j, rxcnt = 0, longest = 0;
  1331.  
  1332.      /* load 'list' array with target strings and their lengths */
  1333.     va_start(argptr, ticks);
  1334.     for (i = 0, wp = list; i < 10; ++i, ++wp)
  1335.     {
  1336.         if ((wp->str = va_arg(argptr, char *)) == NULL)
  1337.             break;
  1338.         if ((wp->len = strlen(wp->str)) == 0)
  1339.             return (i);
  1340.         if (wp->len > longest)
  1341.             longest = wp->len;
  1342.     }
  1343.     wp->str = NULL;
  1344.  
  1345.      /* allocate buffer for incoming chars, start timer */
  1346.     p1 = buf = malloc(longest);   /* buf size is length of longest target */
  1347.     set_timeout(&to, ticks);
  1348.  
  1349.      /* wait for target string or error */
  1350.     while (1)
  1351.     {
  1352.         if (async_rxcnt(&port))         /* if character available */
  1353.         {
  1354.             ch = (char)async_rx(&port);
  1355.             if (qf == 0)
  1356.                 d_ch(ch);
  1357.  
  1358.             if (rxcnt < longest)            /* if "incoming" buf not full */
  1359.             {                                       /* load ch in buf,  */
  1360.                 *p1 = ch;                           /* advance positon  */
  1361.                 if (++rxcnt < longest)
  1362.                     ++p1;
  1363.             }
  1364.             else                            /* if "incoming" buf is full */
  1365.             {                                       /* shuffle left 1 pos, */
  1366.                 memmove(buf, &buf[1], longest);     /* load ch in last pos */
  1367.                 *p1 = ch;
  1368.             }
  1369.             for (wp = list; wp->str; ++wp)  /* check for found target */
  1370.             {                               /* j selects pos in buf to look */
  1371.                 if ((j = rxcnt - wp->len) >= 0
  1372.                  && memicmp(wp->str, &buf[j], wp->len) == 0)
  1373.                 {
  1374.                     free(buf);
  1375.                     return (wp - list);     /* return index if found */
  1376.                 }
  1377.             }
  1378.         }
  1379.         else if (KBHIT && KBREAD == X_ESC)  /* check for local abort */
  1380.         {
  1381.             free(buf);
  1382.             return (X_ESC);
  1383.         }
  1384.         else if (timed_out(&to))            /* check for max time */
  1385.         {
  1386.             free(buf);
  1387.             return (TIMED_OUT);
  1388.         }                                   /* check for lost carrier */
  1389.         else if (checkcarrier && !async_carrier(&port)) /* see comment */
  1390.         {
  1391.             free(buf);
  1392.             return (LOST_CARRIER);
  1393.         }
  1394.     }
  1395. }
  1396.  
  1397. /*/////////////////////////////////////////////////////////
  1398. //  x_ansi -- handler for unrecognized ANSI sequences    //
  1399. //:x_a////////////////////////////////////////////////// */
  1400. void x_ansi(char *ansi_str)
  1401. {
  1402.     register char *p1 = strchr(ansi_str, '\0') - 1;
  1403.     WORD cp;
  1404.     char buf[15];
  1405.  
  1406.     if (*p1 == 'n')     /*  Device Status Report request */
  1407.     {
  1408.         if (*(--p1) == '6')
  1409.         {
  1410.             cp = getcurloc();
  1411.             sprintf(buf, "\x1b[%d;%dR", (cp >> 8) + 1, (cp & 0xff) + 1);
  1412.         }
  1413.         else if (*p1 == '5')
  1414.             strcpy(buf, "\x1b[0n");
  1415.         async_txblk(&port, buf, strlen(buf));
  1416.     }
  1417.     else                /*  unsupported, display in raw mode */
  1418.     {
  1419.         v_ansi = 0;
  1420.         d_str(ansi_str);
  1421.         v_ansi = 1;
  1422.     }
  1423. }
  1424.  
  1425. /*--------------------------------------------+
  1426. |  zmodem message types (defined in ZMDOS.H)  |
  1427. +---------------------------------------------/
  1428. #define M_RHDR      0       // received header
  1429. #define M_SHDR      1       // sent header
  1430. #define M_BLK0      2       // block 0 data processed (name, size, etc.)
  1431. #define M_CLASH     3       // file name clash occurred (use ExistOpts)
  1432. #define M_FILE      4       // start of transfer, FilePos = 1st position
  1433. #define M_EOF       5       // end of transfer (1 file)
  1434. #define M_DATA      6       // sent or received file data packet
  1435. #define M_FLOW      7       // change in XOFF or CTS flow status
  1436. #define M_IDLE      8       // waiting for character or for tx to empty
  1437. #define M_RESET     9       // reset to 'first file' condition */
  1438.  
  1439. /*/////////////////////////////////////////////////////////
  1440. //  ZMsg -- zmodem message handler                       //
  1441. //:zms///////////////////////////////////////////////:z: */
  1442. void ZMsg(int type, ...)
  1443. {
  1444.     static char *HdrType[] =
  1445.     {
  1446.         "Garbage Count", "Long Packet",   "Garbled Packet",   "Bad Crc",
  1447.         "Timed Out",     "Unknown Hdr",   "Sync Error",       "Memory Error",
  1448.         "File Error",    "Lost Carrier",  "Remote Abort",     "Local Abort",
  1449.         "ZRQINIT",       "ZRINIT",        "ZSINIT",           "ZACK",
  1450.         "ZFILE",         "ZSKIP",         "ZNAK",             "ZABORT",
  1451.         "ZFIN",          "ZRPOS",         "ZDATA",            "ZEOF",
  1452.         "ZFERR",         "ZCRC",          "ZCHALLENGE",       "ZCOMPL",
  1453.         "ZCAN",          "ZFREECNT",      "ZCOMMAND",         "ZSTDERR"
  1454.     };
  1455.     static char *HdrStyle[] = { "ZBIN", "ZHEX", "ZBIN32", "" };
  1456.     static char *CrcStyle[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW" };
  1457.     static char MsgMask[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  1458.  
  1459.     static long fStartSec, tStartSec = -1L, fStartHunds, tStartHunds = -1L;
  1460.     static long fCPS, fBytes, tBytes;
  1461.     static long fBarInc, tBarInc, fBarBytes, tBarBytes;
  1462.     static long fSize, fStartPos, updBytes, lastPos, orgTBytes;
  1463.     static long lastSec, temp, flowhalts;
  1464.     static int tBarRow, fBarRow;
  1465.     static char gotBlock, crcType = ZCRCG, firstfile = 1;
  1466.  
  1467.     FILE *flog;
  1468.     va_list argptr;
  1469.     int i, j, row, hdr;
  1470.     long secs;
  1471.     char *p1;
  1472.  
  1473.     if (MsgMask[type] == '\0')
  1474.         return;
  1475.     switch (type)
  1476.     {
  1477.       case M_RHDR:              /* received header */
  1478.       case M_SHDR:              /* sent header */
  1479.         row = (type == M_RHDR) ? 11 : 12;
  1480.         va_start(argptr, type);
  1481.         if ((hdr = va_arg(argptr, int)) < 0)
  1482.             ZHdr.Data = 0L;
  1483.         i = hdr + 12;
  1484.         j = va_arg(argptr, int) - 'A';
  1485.         if (j < 0 || j > 3)
  1486.             j = 3;
  1487.         vDisplay(row, 22, "%-17s%-9s%08lX%11ld", HdrType[i], HdrStyle[j],
  1488.          ZHdr.Data, ZHdr.Data);
  1489.         break;
  1490.       case M_CLASH:             /* file name clash occurred */
  1491.         if (TFlag.F.ExistOpts != 2)
  1492.             break;  /* not new name */
  1493.       case M_BLK0:              /* sent or received block 0 */
  1494.         if (OverrideName != NULL && TFlag.F.Receiving && type != M_CLASH)
  1495.         {
  1496.             if (OverrideFlag == '/')
  1497.                 strcpy(PathName, OverrideName);
  1498.             else
  1499.                 strcpy(NameExt, GetNameExt(OverrideName));
  1500.         }
  1501.         i = sprintf(buf, "%-52s", PathName) - 52;
  1502.         DspMsgAt[qf](3, 17, color[3], &(strupr(buf))[i]);
  1503.         if (type == M_CLASH)
  1504.             break;
  1505.         v_color = txtcolor;
  1506.         flowhalts = 0L;
  1507.         if (qf == 0)
  1508.         {
  1509.             scrlupat(5, 22, 6, 32, 0);
  1510.             scrlupat(5, 58, 7, 68, 0);
  1511.         }
  1512.         fSize = (TFlag.F.Receiving) ? RxdFileSize : FileSize;
  1513.         vDisplay(6, 58, "%-8ld", fSize);
  1514.         fStartHunds = getHunds();
  1515.         fStartSec = uldiv(fStartHunds, 100L);
  1516.         if (firstfile)
  1517.         {
  1518.             firstfile = tFiles = 0;
  1519.             tBytes = tBarBytes = 0L;
  1520.             lastSec = tStartSec = fStartSec;
  1521.             tStartHunds = fStartHunds;
  1522.             tBarRow = 21;
  1523.             if ((tBarInc = uldiv(TotalBytes, 19L)) == 0)
  1524.                 ++tBarInc;
  1525.             orgTBytes = TotalBytes;
  1526.             if ((tCPS = uldiv(ulmul(ConnectBaud, 955L), 10000L)) == 0L)
  1527.                 ++tCPS;
  1528.             vDisplay(17, 61, "%-8s",
  1529.              ConvertSecs(uldiv(TotalBytes, tCPS) + (TotalFiles >> 2)));
  1530.         }
  1531.         if ((fBarInc = uldiv(fSize, 19L)) == 0)
  1532.             ++fBarInc;
  1533.         fBarBytes = 0L, fBarRow = 21;
  1534.         if (qf == 0)
  1535.             d_nchat(3, 73, '▒', color[4], 19, 0);
  1536.         if (orgTBytes != 0L)
  1537.         {
  1538.             j = 3 + (int)((orgTBytes & 0xffff0000L) ?
  1539.              uldiv(TotalBytes, uldiv(orgTBytes, 19L)) :
  1540.              uldiv(ulmul(TotalBytes, 19L), orgTBytes));
  1541.             while (j < tBarRow && tBarRow > 2)
  1542.                 DspMsgAt[qf](tBarRow--, 75, color[6], "▒");
  1543.             vDisplay(17, 26, "%-4d", TotalFiles - 1);
  1544.             vDisplay(18, 26, "%-8ld", TotalBytes - fSize);
  1545.         }
  1546.         else
  1547.         {
  1548.             tBarInc = fBarInc, tBarBytes = 0L, tBarRow = 21;
  1549.             if (qf == 0)
  1550.                 d_nchat(3, 75, '▒', color[4], 19, 0);
  1551.         }
  1552.         break;
  1553.       case M_EOF:               /* end of file transfer */
  1554.         va_start(argptr, type);
  1555.         i = va_arg(argptr, int);
  1556.         if (i == ZEOF || i == ZRINIT)
  1557.         {
  1558.             vDisplay(20, 26, "%d", ++tFiles);
  1559.             tfBytes = tBytes;
  1560.             if (((p1 = getenv("TXZMLOG")) != NULL)
  1561.              && ((flog = fopen(p1, "at")) != NULL))
  1562.             {
  1563.                 sprintf(buf,
  1564.                  "%c %6ld %5ld bps %4ld cps %3u errors %5ld %4d %s %d\n",
  1565.                  TFlag.F.Receiving ? 'Z' : 'z', FilePos, ConnectBaud, fCPS,
  1566.                  ErrCnt, flowhalts, BlkLen, NameExt, (SerNbr) ? SerNbr : -1);
  1567.                 fputs(buf, flog);
  1568.                 fclose(flog);
  1569.             }
  1570.         }
  1571.         if (orgTBytes != 0L)
  1572.         {
  1573.             temp = TotalBytes - fSize;
  1574.             j = 3 + (int)((orgTBytes & 0xffff0000L) ?
  1575.              uldiv(temp, uldiv(orgTBytes, 19L)) :
  1576.              uldiv(ulmul(temp, 19L), orgTBytes));
  1577.             while (j < tBarRow && tBarRow > 2)
  1578.                 DspMsgAt[qf](tBarRow--, 75, color[6], "▒");
  1579.         }
  1580.         crcType = ZCRCG;
  1581.         break;
  1582.       case M_FILE:              /* start of transfer, 1st FilePos set */
  1583.         lastPos = fStartPos = FilePos;
  1584.         fBytes = 0L;
  1585.         vDisplay(5, 22, "%-8s", ConvertSecs(uldiv(fSize - fStartPos, tCPS)));
  1586.         vDisplay(7, 58, "%-8ld", fStartPos);
  1587.         if (fStartPos == 0L)
  1588.             break;
  1589.         updBytes = fStartPos;
  1590.       case M_DATA:              /* sent or received file data packet */
  1591.         if (type != M_FILE)
  1592.         {
  1593.             gotBlock = 1;
  1594.             updBytes = FilePos - lastPos;
  1595.             lastPos = FilePos;
  1596.             fBytes += updBytes, tBytes += updBytes;
  1597.             vDisplay(5, 58, "%-8ld", FilePos);
  1598.             vDisplay(21, 26, "%-8ld", tBytes);
  1599.             va_start(argptr, type);
  1600.             vDisplay(14, 11, "%s-%s", (BinHdr == ZBIN32) ? "32" : "16",
  1601.              CrcStyle[(crcType = (char)va_arg(argptr, int)) - ZCRCE]);
  1602.         }
  1603.         fBarBytes += updBytes;
  1604.         tBarBytes += updBytes;
  1605.         while (fBarBytes >= fBarInc && fBarRow > 2)
  1606.             fBarBytes -= fBarInc, DspMsgAt[qf](fBarRow--, 73, color[5], "▒");
  1607.         while (tBarBytes >= tBarInc && tBarRow > 2)
  1608.             tBarBytes -= tBarInc, DspMsgAt[qf](tBarRow--, 75, color[6], "▒");
  1609.         break;
  1610.       case M_FLOW:
  1611.         va_start(argptr, type);
  1612.         switch (i = va_arg(argptr, int))
  1613.         {
  1614.           case 0:           /* XOFF cleared (XON received) */
  1615.           case 1:           /* XOFF received */
  1616.             DspMsgAt[qf](14, 44, color[3], (i) ? "XOFF" : "    ");
  1617.             break;
  1618.           case 2:           /* CTS signal raised */
  1619.           case 3:           /* CTS signal lowered */
  1620.             DspMsgAt[qf](14, 49, color[3], (i == 3) ? "CTS" : "   ");
  1621.             break;
  1622.           case 4:           /* port error */
  1623.             DspMsgAt[qf](14, 55, color[3]|BLNK, "PORT RESET");
  1624.             tdelay(18);
  1625.             DspMsgAt[qf](14, 55, color[3], "          ");
  1626.         }
  1627.         flowhalts += (i & 1);
  1628.         break;
  1629.       case M_IDLE:
  1630.         if (firstfile || ((secs = getSeconds()) == fStartSec))
  1631.             break;
  1632.         if (gotBlock || crcType == ZCRCE)
  1633.         {
  1634.             gotBlock = 0;
  1635.             if (fBytes & 0xffff0000L)
  1636.                 fCPS = uldiv(fBytes, secs - fStartSec);
  1637.             else
  1638.                 fCPS = uldiv(ulmul(fBytes, 100L), getHunds() - fStartHunds);
  1639.             if (tBytes & 0xffff0000L)
  1640.                 tCPS = uldiv(tBytes, secs - tStartSec);
  1641.             else
  1642.                 tCPS = uldiv(ulmul(tBytes, 100L), getHunds() - tStartHunds);
  1643.             if (tCPS == 0)
  1644.                 ++tCPS;
  1645.             vDisplay(7, 22, "%-6ld", fCPS);
  1646.             vDisplay(21, 61, "%-6ld", tCPS);
  1647.         }
  1648.         if (secs != lastSec)
  1649.         {
  1650.             lastSec = secs;
  1651.             DspMsgAt[qf](6, 22, txtcolor, ConvertSecs(secs - fStartSec));
  1652.             DspMsgAt[qf](18, 61, txtcolor, ConvertSecs(secs - tStartSec));
  1653.         }
  1654.         if (tryDV)
  1655.             DV_TimeSlice();
  1656.         break;
  1657.       case M_RESET:
  1658.         if (cfg.MsrFlow && !async_cts(&port))
  1659.             DspMsgAt[qf](14, 49, color[3], "CTS");
  1660.         crcType = ZCRCG, firstfile = 1;
  1661.         tStartSec = PrevSecs = PrevHunds = -1L;
  1662.         break;
  1663.     }
  1664. }
  1665.  
  1666.